#include "knight.h"

int solutions_count = 0;

board::board ()
{
    fill_n ((int*) chess_board, SIZE*SIZE, 0);
}

board::board (board& Cersei)
{
    copy ((int*) Cersei.chess_board, 
          (int*) Cersei.chess_board + SIZE * SIZE,
          (int*) chess_board);
}

void board::print ()
{
    int i, j;
    cout << endl << setw(4) << "";
    for (i = 0; i < SIZE; ++i)
        cout << setw (3) << i;
    cout << endl;
    for (i = 0; i < SIZE; ++i)
    {
        cout << setw (4) << i;
        for (j = 0; j < SIZE; ++j)
            cout << setw (3) << chess_board[i][j];
        cout << endl;
    }
    cout << endl;
}

int* board::operator [] (int index)
{
    return chess_board[index];
}

knight::knight (int nx, int ny)
{
    flags = PRINT_ALL;
    ori_x = x = nx;
    ori_y = y = ny;
    count = 0;
    copy ((int*) ::acceci, (int*) ::acceci + SIZE*SIZE,
          (int*) acceci);
}

knight::knight (knight& Jorah_Mormont)
{
    flags = Jorah_Mormont.flags;
    ori_x = Jorah_Mormont.ori_x;
    ori_y = Jorah_Mormont.ori_y;
    x = Jorah_Mormont.x;
    y = Jorah_Mormont.y;
    count = Jorah_Mormont.count;
    chess_board = Jorah_Mormont.chess_board;
    copy ((int*) Jorah_Mormont.acceci, 
          (int*) Jorah_Mormont.acceci + SIZE*SIZE,
          (int*) acceci);
}

void knight::move (int move_number)
{
    if ( y + vertil[move_number] < SIZE &&
         y + vertil[move_number] >= 0 &&
         x + horizl[move_number] < SIZE &&
         x + horizl[move_number] >= 0)
    {
        count++;
        y += vertil[move_number];
        x += horizl[move_number];

        chess_board[y][x] = count;

        refresh_access();
    }
}

void knight::compute (int move_number)
{
    if (-1 != move_number)
    {
        move (move_number);
        if (SIZE*SIZE == count) //successful
        {
            solutions_count++;

            if (flags == PRINT_ALL)  
                chess_board.print ();
            else if (flags == PRINT_NONE)
                ;
            else if (flags == PRINT_FULL)
                if (x == ori_x && y == ori_y)
                    chess_board.print ();
            return;
        }
    }

    int minimus = 9;
    vector<int> mins;

    int i, j;

    for (i = 0; i < 8; ++i)
    {
        int foo = access(i);
        if (foo < 0) 
            continue;
        else 
            if (foo < minimus) 
                minimus = foo;
    }

    if (9 == minimus) 
        return; //this move failed

    for (i = 0; i < 8; ++i)
        if (access(i) == minimus)
            mins.push_back(i);

    for (j = 0; j < (signed)mins.size (); ++j)
    {
        knight Robort_Stark (*this);
        Robort_Stark.compute (mins[j]);
    }

}

void knight::refresh_access ()
{
    int i;
    for (i = 0; i < 8; ++i)
        if (access (i) > -2)
            acceci[y + vertil[i]][x + horizl[i]]--;
}

int knight::access (int move_number)
{
    if ( y + vertil[move_number] < SIZE &&
         y + vertil[move_number] >= 0 &&
         x + horizl[move_number] < SIZE &&
         x + horizl[move_number] >= 0)
    {
        int nx = x, ny = y;
        ny += vertil[move_number];
        nx += horizl[move_number];
        if (chess_board[ny][nx] != 0)
            return -1; //this has been visited
        else
            return acceci[ny][nx];
    } 
    else 
        return -2; //invalid move number;
}

void knight::print_access ()
{
    int i, j;
    cout << endl << setw(4) << "";
    for (i = 0; i < SIZE; ++i)
        cout << setw (3) << i;
    cout << endl;
    for (i = 0; i < SIZE; ++i)
    {
        cout << setw (4) << i;
        for (j = 0; j < SIZE; ++j)
            cout << setw (3) << acceci[i][j];
        cout << endl;
    }
    cout << endl;
}

